﻿using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using OAuthApp.Tenant;
using Swashbuckle.AspNetCore.Annotations;
using System.IO;
using OAuthApp.Data;
using OAuthApp.Filters;
using OAuthApp.Services;
using Microsoft.AspNetCore.Hosting;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;

namespace OAuthApp.Apis
{
    [SwaggerTag("租户")]
    [ServiceFilter(typeof(ApiRequestLoggingAttribute))]
    public class TenantsController : BaseController
    {
        private readonly TenantDbContext _context;
        private readonly AppDbContext _appContext;
        private readonly ApiDbContext _apiContext;
        private readonly UploadService _uploader;
        private readonly IWebHostEnvironment _env;

        public TenantsController(TenantDbContext context, 
            AppDbContext appContext,
            ApiDbContext apiContext,
            UploadService uploader,
            IWebHostEnvironment env)
        {
            _context = context;
            _appContext = appContext;
            _apiContext = apiContext;
            _uploader = uploader;
            _env = env;
        }

        [HttpGet]
        [SwaggerOperation(OperationId = "Tenants")]
        [EncryptResultFilter]
        public IActionResult List()
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            var result = _context.Tenants
               .Where(x => !x.IsDelete && x.OwnerId == UserID && x.OwnerHost == Request.Host.Host)
               .OrderByDescending(x => x.ID).ToList();

            return OK(result);
        }

        [HttpGet("{id}")]
        [SwaggerOperation(OperationId = "Tenant")]
        [EncryptResultFilter]
        public IActionResult Get(long id)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            var tenant = _context.Tenants
                .Where(x => x.ID == id && x.OwnerId == UserID)
                .FirstOrDefault();

            if (tenant == null)
            {
                return NotFound();
            }

            var path = AppConst.TenantDBPath + "\\" + tenant.OwnerHost + ".db";

            try
            {
                using (var dbFile = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    tenant.DatabaseSize = dbFile.Length;
                    tenant.LastUpdate = DateTime.Now;
                    _context.SaveChanges();
                }
            }
            catch { }

            var appSize = _context.TenantOrders
                .Where(x => x.TenantID == id && x.ChannelCode == ChannelCodes.App).Sum(x => x.Amount);

            var appBlobSize = _context.TenantOrders
              .Where(x => x.TenantID == id && x.ChannelCode == ChannelCodes.AppBlob).Sum(x => x.Amount);

            var appVersionSize = _context.TenantOrders
                .Where(x => x.TenantID == id && x.ChannelCode == ChannelCodes.AppVersion).Sum(x => x.Amount);

            return OK(new
            {
                tenant,
                database = new { size = tenant.DatabaseSize },
                appServer = new { size = appSize },
                blobServer = new { size = appBlobSize },
                releaseServer = new { size = appVersionSize }
            });
        }

        [HttpPut("{id}")]
        [SwaggerOperation(OperationId = "TenantPut")]
        public IActionResult Put(long id, Tenant.Tenant tenant)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            if (id != tenant.ID ||
                !_context.Tenants.Any(x => x.ID == id && (x.OwnerId == UserID)))
            {
                return NotFound();
            }

            _context.Entry(tenant).State = EntityState.Modified;

            try
            {
                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                return Error(ex.Message);
            }

            return OK(true);
        }

        [HttpGet("CheckVersion")]
        [SwaggerOperation(OperationId = "TenantCheckVersion")]
        [EncryptResultFilter]
        public IActionResult CheckVersion(string channelCode,bool checkOnly = true)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            if (channelCode.Equals(ChannelCodes.App))
            {
                if (!checkOnly)
                {
                    var appNewMigrations = _appContext.Database.GetPendingMigrations().ToList();

                    if (appNewMigrations.Count > 0)
                    {
                        try
                        {
                            _appContext.Database.Migrate();
                        }
                        catch(Exception ex)
                        {
                            return Error(ex.Message);
                        }
                    }
                }

                return OK(new
                {
                    versions = _appContext.Database.GetAppliedMigrations(),
                    newVersions = _appContext.Database.GetPendingMigrations()
                });
            }

            if (channelCode.Equals(ChannelCodes.Api))
            {
                if (!checkOnly)
                {
                    var apiNewMigrations = _apiContext.Database.GetPendingMigrations().ToList();

                    if (apiNewMigrations.Count > 0)
                    {
                        try
                        {
                            _apiContext.Database.Migrate();
                        }
                        catch (Exception ex)
                        {
                            return Error(ex.Message);
                        }
                    }
                }

                return OK(new
                {
                    versions = _apiContext.Database.GetAppliedMigrations(),
                    newVersions = _apiContext.Database.GetPendingMigrations()
                });
            }

            if (channelCode.Equals(ChannelCodes.Tenant))
            {
                if (!checkOnly)
                {
                    var tenantNewMigrations = _context.Database.GetPendingMigrations().ToList();

                    if (tenantNewMigrations.Count > 0)
                    {
                        try
                        {
                            _context.Database.Migrate();
                        }
                        catch (Exception ex)
                        {
                            return Error(ex.Message);
                        }
                    }
                }

                return OK(new
                {
                    versions = _context.Database.GetAppliedMigrations(),
                    newVersions = _context.Database.GetPendingMigrations()
                });
            }

            return OK(true);
        }

        [HttpPost("Backup")]
        [SwaggerOperation(OperationId = "TenantBackup")]
        [EncryptResultFilter]
        public IActionResult Backup(long id)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            var tenant = _context.Tenants
               .Where(x => x.ID == id && x.OwnerId == UserID)
               .FirstOrDefault();

            if (tenant == null)
            {
                return NotFound();
            }

            var fromPath = AppConst.TenantDBPath + "\\" + tenant.OwnerHost + ".db";

            try
            {
                var fileName = DateTime.Now.ToString("yyyyMMddHHmmss");

                var savePath = $"{tenant.ID}/{ChannelCodes.Database}/{fileName}.zip";

                var (copyResult,fileLength) = _uploader.CopyTo(fromPath, savePath);

                #region 累计应用文件用量
                _context.TenantOrders.Add(new TenantOrder()
                {
                    Amount = fileLength,
                    ChannelAppID = tenant.ID.ToString(),
                    ChannelCode = ChannelCodes.AppBlob,
                    TenantID = tenant.ID
                });
                _context.SaveChanges();
                #endregion

                return OK(AppConst.BlobServer + "/" + savePath);
            }
            catch(Exception ex) 
            {
                return Error(ex.Message);
            }
        }

        [HttpGet("Backups")]
        [SwaggerOperation(OperationId = "TenantBackups")]
        [EncryptResultFilter]
        public IActionResult Backups(long id)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            var tenant = _context.Tenants
               .Where(x => x.ID == id && x.OwnerId == UserID)
               .FirstOrDefault();

            if (tenant == null)
            {
                return NotFound();
            }

            var fileFolder = $"{tenant.ID}/{ChannelCodes.Database}";

            var path = Path.Combine(_env.WebRootPath, "blobs", fileFolder);

            if (!Directory.Exists(path))
            {
                return OK(new List<string>());
            }

            var files = Directory.GetFiles(path).Select(x => Path.GetFileName(x))
                .OrderByDescending(x => x);

            return OK(files);
        }

        [HttpPost("Rollback")]
        [SwaggerOperation(OperationId = "TenantRollback")]
        [EncryptResultFilter]
        public IActionResult Rollback(long id,string version)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            var tenant = _context.Tenants
               .Where(x => x.ID == id && x.OwnerId == UserID)
               .FirstOrDefault();

            if (tenant == null)
            {
                return NotFound();
            }

            var filePath = $"{tenant.ID}/{ChannelCodes.Database}/{version}.zip";

            var fromPath = Path.Combine(_env.WebRootPath, "blobs", filePath);

            if (!System.IO.File.Exists(fromPath))
            {
                return Error("备份文件不存在");
            }

            var savePath = AppConst.TenantDBPath + "\\" + tenant.OwnerHost + ".db";

            try
            {
                var fs = new FileInfo(fromPath);

                fs.CopyTo(savePath, true);

                return OK(true);
            }
            catch (Exception ex)
            {
                return Error(ex.Message);
            }
        }

        [HttpDelete("Backup")]
        [SwaggerOperation(OperationId = "TenantBackupDelete")]
        [EncryptResultFilter]
        public IActionResult BackupDelete(long id, string version)
        {
            if (!IsAdmin)
            {
                return Error("权限不足");
            }

            var tenant = _context.Tenants
               .Where(x => x.ID == id && x.OwnerId == UserID)
               .FirstOrDefault();

            if (tenant == null)
            {
                return NotFound();
            }

            var filePath = $"{tenant.ID}/{ChannelCodes.Database}/{version}.zip";

            var fromPath = Path.Combine(_env.WebRootPath, "blobs", filePath);

            try
            {
                if (System.IO.File.Exists(fromPath))
                {
                    System.IO.File.Delete(fromPath);
                }

                return OK(true);
            }
            catch (Exception ex)
            {
                return Error(ex.Message);
            }
        }

    }
}
